#ifndef __PINFUN_H
#define __PINFUN_H

#include "bsp.h"
#include "pintype.h"
#include "mytype.h"

/*******************************************************************************
 * @brief   IO位带区映射
 *******************************************************************************/
// IO口操作,只对单一的IO口
#define PAout(n) _VMEM32(CORTEXM_BITBAND_REG(GPIOA->odt, n)) //输出
#define PAin(n) _VMEM32(CORTEXM_BITBAND_REG(GPIOA->idt, n)) //输入

#define PBout(n) _VMEM32(CORTEXM_BITBAND_REG(GPIOB->odt, n)) //输出
#define PBin(n) _VMEM32(CORTEXM_BITBAND_REG(GPIOB->idt, n)) //输入

#define PCout(n) _VMEM32(CORTEXM_BITBAND_REG(GPIOC->odt, n)) //输出
#define PCin(n) _VMEM32(CORTEXM_BITBAND_REG(GPIOC->idt, n)) //输入

#define PDout(n) _VMEM32(CORTEXM_BITBAND_REG(GPIOD->odt, n)) //输出
#define PDin(n) _VMEM32(CORTEXM_BITBAND_REG(GPIOD->idt, n)) //输入

#define PEout(n) _VMEM32(CORTEXM_BITBAND_REG(GPIOE->odt, n)) //输出
#define PEin(n) _VMEM32(CORTEXM_BITBAND_REG(GPIOE->idt, n)) //输入

#define PFout(n) _VMEM32(CORTEXM_BITBAND_REG(GPIOF->odt, n)) //输出
#define PFin(n) _VMEM32(CORTEXM_BITBAND_REG(GPIOF->idt, n)) //输入

#define PGout(n) _VMEM32(CORTEXM_BITBAND_REG(GPIOG->odt, n)) //输出
#define PGin(n) _VMEM32(CORTEXM_BITBAND_REG(GPIOG->idt, n)) //输入

/*******************************************************************************
 * @brief   端口
 *******************************************************************************/
#define PA_PORT GPIOA
#define PB_PORT GPIOB
#define PC_PORT GPIOC
#define PD_PORT GPIOD
#define PE_PORT GPIOE
#define PF_PORT GPIOF
#define PG_PORT GPIOG
#define PH_PORT GPIOH

/*******************************************************************************
 * @brief   功能
 *******************************************************************************/
void bsp_gpio_mode_out_pp(gpio_type *port, uint8_t pin);
void bsp_gpio_mode_out_od(gpio_type *port, uint8_t pin);
void bsp_gpio_mode_in_up(gpio_type *port, uint8_t pin);
void bsp_gpio_mode_in_dn(gpio_type *port, uint8_t pin);
void bsp_gpio_mode_in_ft(gpio_type *port, uint8_t pin);
void bsp_gpio_mode_set(gpio_type *port, uint8_t pin, char pm);

#define gpio_out_high(port, pin) port##out(pin) = 1
#define gpio_out_low(port, pin) port##out(pin) = 0
#define gpio_out_tog(port, pin) port##out(pin) = !port##out(pin)
#define gpio_out_set(port, pin, st) port##out(pin) = (st)
#define gpio_out_get(port, pin) port##out(pin)
#define gpio_in_get(port, pin) port##in(pin)

#define gpio_mode_set(port, pin, pm) bsp_gpio_mode_set(port##_PORT, pin, pm)
#define gpio_dir_in_ft(port, pin) bsp_gpio_mode_in_ft(port##_PORT, pin)
#define gpio_dir_in_dn(port, pin) bsp_gpio_mode_in_dn(port##_PORT, pin)
#define gpio_dir_in_up(port, pin) bsp_gpio_mode_in_up(port##_PORT, pin)
#define gpio_dir_out_pp(port, pin) bsp_gpio_mode_out_pp(port##_PORT, pin)
#define gpio_dir_out_od(port, pin) bsp_gpio_mode_out_od(port##_PORT, pin)

/*******************************************************************************
 * @brief   同相IO定义
 *******************************************************************************/
#ifndef PORT_PIN_CTEAT
#define port_fun_pin_make(name, port, pin) \
	extern const port_fun_pin_type name
#else
#define port_fun_pin_make(name, port, pin)                              \
	void name##_pin_en(void) { gpio_out_high(port, pin); }              \
	void name##_pin_dis(void) { gpio_out_low(port, pin); }              \
	void name##_pin_out(uint8_t st) { gpio_out_set(port, pin, st); }    \
	void name##_pin_tog(void) { gpio_out_tog(port, pin); }              \
	uint8_t name##_pin_out_st(void) { return gpio_out_get(port, pin); } \
	uint8_t name##_pin_in_st(void) { return gpio_in_get(port, pin); }   \
	void name##_mode_set(char pm) { gpio_mode_set(port, pin, pm); }     \
	const port_fun_pin_type name = {                                    \
		name##_pin_en,                                                  \
		name##_pin_dis,                                                 \
		name##_pin_out,                                                 \
		name##_pin_tog,                                                 \
		name##_pin_out_st,                                              \
		name##_pin_in_st,                                               \
		name##_mode_set}
#endif

/*******************************************************************************
 * @brief   反相IO定义
 *******************************************************************************/
#ifndef PORT_PIN_CTEAT
#define port_nfun_pin_make(name, port, pin) \
	extern const port_fun_pin_type name
#else
#define port_nfun_pin_make(name, port, pin)                              \
	void name##_pin_en(void) { gpio_out_low(port, pin); }                \
	void name##_pin_dis(void) { gpio_out_high(port, pin); }              \
	void name##_pin_out(uint8_t st) { gpio_out_set(port, pin, !st); }    \
	void name##_pin_tog(void) { gpio_out_tog(port, pin); }               \
	uint8_t name##_pin_out_st(void) { return !gpio_out_get(port, pin); } \
	uint8_t name##_pin_in_st(void) { return !gpio_in_get(port, pin); }   \
	void name##_mode_set(char pm) { gpio_mode_set(port, pin, pm); }      \
	const port_fun_pin_type name = {                                     \
		name##_pin_en,                                                   \
		name##_pin_dis,                                                  \
		name##_pin_out,                                                  \
		name##_pin_tog,                                                  \
		name##_pin_out_st,                                               \
		name##_pin_in_st,                                                \
		name##_mode_set}
#endif

/*******************************************************************************
 * @brief   同相IO定义-IO
 *******************************************************************************/
#ifndef PORT_PIN_CTEAT
#define port_io_pin_make(name, port, pin) \
	extern const port_io_pin_type name
#else
#define port_io_pin_make(name, port, pin)                               \
	void name##_pin_en(void) { gpio_out_high(port, pin); }              \
	void name##_pin_dis(void) { gpio_out_low(port, pin); }              \
	void name##_pin_out(uint8_t st) { gpio_out_set(port, pin, st); }    \
	void name##_pin_tog(void) { gpio_out_tog(port, pin); }              \
	uint8_t name##_pin_out_st(void) { return gpio_out_get(port, pin); } \
	uint8_t name##_pin_in_st(void) { return gpio_in_get(port, pin); }   \
	void name##_dir_in_ft(void) { gpio_dir_in_ft(port, pin); }          \
	void name##_dir_in_up(void) { gpio_dir_in_up(port, pin); }          \
	void name##_dir_out_pp(void) { gpio_dir_out_pp(port, pin); }        \
	void name##_dir_out_od(void) { gpio_dir_out_od(port, pin); }        \
	const port_io_pin_type name = {                                     \
		name##_pin_en,                                                  \
		name##_pin_dis,                                                 \
		name##_pin_out,                                                 \
		name##_pin_tog,                                                 \
		name##_pin_out_st,                                              \
		name##_pin_in_st,                                               \
		name##_dir_in_ft,                                               \
		name##_dir_in_up,                                               \
		name##_dir_out_pp,                                              \
		name##_dir_out_od}
#endif

/*******************************************************************************
 * @brief   反相IO定义
 *******************************************************************************/
#ifndef PORT_PIN_CTEAT
#define port_nio_pin_make(name, port, pin) \
	extern const port_io_pin_type name
#else
#define port_nio_pin_make(name, port, pin)                               \
	void name##_pin_en(void) { gpio_out_low(port, pin); }                \
	void name##_pin_dis(void) { gpio_out_high(port, pin); }              \
	void name##_pin_out(uint8_t st) { gpio_out_set(port, pin, !st); }    \
	void name##_pin_tog(void) { gpio_out_tog(port, pin); }               \
	uint8_t name##_pin_out_st(void) { return !gpio_out_get(port, pin); } \
	uint8_t name##_pin_in_st(void) { return !gpio_in_get(port, pin); }   \
	void name##_dir_in_ft(void) { gpio_dir_in_ft(port, pin); }           \
	void name##_dir_in_up(void) { gpio_dir_in_up(port, pin); }           \
	void name##_dir_out_pp(void) { gpio_dir_out_pp(port, pin); }         \
	void name##_dir_out_od(void) { gpio_dir_out_od(port, pin); }         \
	const port_io_pin_type name = {                                      \
		name##_pin_en,                                                   \
		name##_pin_dis,                                                  \
		name##_pin_out,                                                  \
		name##_pin_tog,                                                  \
		name##_pin_out_st,                                               \
		name##_pin_in_st,                                                \
		name##_dir_in_ft,                                                \
		name##_dir_in_up,                                                \
		name##_dir_out_pp,                                               \
		name##_dir_out_od}
#endif

/*******************************************************************************
 * @brief   同相OUT定义
 *******************************************************************************/
#ifndef PORT_PIN_CTEAT
#define port_out_pin_make(name, port, pin)  \
	extern const port_out_pin_type name;    \
	extern void name##_pin_en(void);        \
	extern void name##_pin_dis(void);       \
	extern void name##_pin_out(uint8_t st); \
	extern void name##_pin_tog(void);       \
	extern uint8_t name##_pin_out_st(void);
#else
#define port_out_pin_make(name, port, pin)                              \
	void name##_pin_en(void) { gpio_out_high(port, pin); }              \
	void name##_pin_dis(void) { gpio_out_low(port, pin); }              \
	void name##_pin_out(uint8_t st) { gpio_out_set(port, pin, st); }    \
	void name##_pin_tog(void) { gpio_out_tog(port, pin); }              \
	uint8_t name##_pin_out_st(void) { return gpio_out_get(port, pin); } \
	void name##_dir_out_pp(void) { gpio_dir_out_pp(port, pin); }        \
	void name##_dir_out_od(void) { gpio_dir_out_od(port, pin); }        \
	const port_out_pin_type name = {                                    \
		name##_pin_en,                                                  \
		name##_pin_dis,                                                 \
		name##_pin_out,                                                 \
		name##_pin_tog,                                                 \
		name##_pin_out_st}
#endif

/*******************************************************************************
 * @brief   反相OUT定义
 *******************************************************************************/
#ifndef PORT_PIN_CTEAT
#define port_nout_pin_make(name, port, pin) \
	extern const port_out_pin_type name;    \
	extern void name##_pin_en(void);        \
	extern void name##_pin_dis(void);       \
	extern void name##_pin_out(uint8_t st); \
	extern void name##_pin_tog(void);       \
	extern uint8_t name##_pin_out_st(void);
#else
#define port_nout_pin_make(name, port, pin)                              \
	void name##_pin_en(void) { gpio_out_low(port, pin); }                \
	void name##_pin_dis(void) { gpio_out_high(port, pin); }              \
	void name##_pin_out(uint8_t st) { gpio_out_set(port, pin, (!st)); }  \
	void name##_pin_tog(void) { gpio_out_tog(port, pin); }               \
	uint8_t name##_pin_out_st(void) { return !gpio_out_get(port, pin); } \
	void name##_dir_out_pp(void) { gpio_dir_out_pp(port, pin); }         \
	void name##_dir_out_od(void) { gpio_dir_out_od(port, pin); }         \
	const port_out_pin_type name = {                                     \
		name##_pin_en,                                                   \
		name##_pin_dis,                                                  \
		name##_pin_out,                                                  \
		name##_pin_tog,                                                  \
		name##_pin_out_st}
#endif

/*******************************************************************************
 * @brief   同相IN定义
 *******************************************************************************/
#ifndef PORT_PIN_CTEAT
#define port_in_pin_make(name, port, pin) \
	extern const port_in_pin_type name
#else
#define port_in_pin_make(name, port, pin)                             \
	uint8_t name##_pin_in_st(void) { return gpio_in_get(port, pin); } \
	const port_in_pin_type name = {                                   \
		name##_pin_in_st,                                             \
	}
#endif

/*******************************************************************************
 * @brief   反相IN定义
 *******************************************************************************/
#ifndef PORT_PIN_CTEAT
#define port_nin_pin_make(name, port, pin) \
	extern const port_in_pin_type name;    \
	extern uint8_t name##_pin_in_st(void)
#else
#define port_nin_pin_make(name, port, pin)                             \
	uint8_t name##_pin_in_st(void) { return !gpio_in_get(port, pin); } \
	const port_in_pin_type name = {                                    \
		name##_pin_in_st}
#endif

/*******************************************************************************
 * @brief   外部扩展IO
 *******************************************************************************/
#ifdef PORT_PIN_CTEAT
uint8_t ext_port_out[6][8];
uint8_t ext_port_in[4];
#else
extern uint8_t ext_port_out[6][8];
extern uint8_t ext_port_in[4];
#endif
extern uint8_t ext_io_out_get(char gp);

/*******************************************************************************
 * @brief   同相IO定义
 *******************************************************************************/
#ifndef PORT_PIN_CTEAT
#define ext_io_pin_make(name, port, pin)    \
	extern const port_out_pin_type name;    \
	extern void name##_pin_en(void);        \
	extern void name##_pin_dis(void);       \
	extern void name##_pin_out(uint8_t st); \
	extern void name##_pin_tog(void);       \
	extern uint8_t name##_pin_out_st(void);
#else
#define ext_io_pin_make(name, port, pin)                                              \
	void name##_pin_en(void) { ext_port_out[port][pin] = 1; }                         \
	void name##_pin_dis(void) { ext_port_out[port][pin] = 0; }                        \
	void name##_pin_out(uint8_t st) { ext_port_out[port][pin] = st; }                 \
	void name##_pin_tog(void) { ext_port_out[port][pin] = !ext_port_out[port][pin]; } \
	uint8_t name##_pin_out_st(void) { return ext_port_out[port][pin]; }               \
	const port_out_pin_type name = {                                                  \
		name##_pin_en,                                                                \
		name##_pin_dis,                                                               \
		name##_pin_out,                                                               \
		name##_pin_tog,                                                               \
		name##_pin_out_st}
#endif

/*******************************************************************************
 * @brief   反相IO定义
 *******************************************************************************/
#ifndef PORT_PIN_CTEAT
#define ext_nio_pin_make(name, port, pin)   \
	extern const port_out_pin_type name;    \
	extern void name##_pin_en(void);        \
	extern void name##_pin_dis(void);       \
	extern void name##_pin_out(uint8_t st); \
	extern void name##_pin_tog(void);       \
	extern uint8_t name##_pin_out_st(void);
#else
#define ext_nio_pin_make(name, port, pin)                                             \
	void name##_pin_en(void) { ext_port_out[port][pin] = 0; }                         \
	void name##_pin_dis(void) { ext_port_out[port][pin] = 1; }                        \
	void name##_pin_out(uint8_t st) { ext_port_out[port][pin] = !st; }                \
	void name##_pin_tog(void) { ext_port_out[port][pin] = !ext_port_out[port][pin]; } \
	uint8_t name##_pin_out_st(void) { return !ext_port_out[port][pin]; }              \
	const port_out_pin_type name = {                                                  \
		name##_pin_en,                                                                \
		name##_pin_dis,                                                               \
		name##_pin_out,                                                               \
		name##_pin_tog,                                                               \
		name##_pin_out_st}
#endif

/*******************************************************************************
 * @brief   同相IN定义
 *******************************************************************************/
#ifndef PORT_PIN_CTEAT
#define ext_in_pin_make(name, port, pin) \
	extern const port_in_pin_type name;  \
	extern uint8_t name##_pin_in_st(void)
#else
#define ext_in_pin_make(name, port, pin)                                           \
	uint8_t name##_pin_in_st(void) { return ((ext_port_in[port] >> pin) & 0x01); } \
	const port_in_pin_type name = {                                                \
		name##_pin_in_st,                                                          \
	}
#endif

/*******************************************************************************
 * @brief   反相IN定义
 *******************************************************************************/
#ifndef PORT_PIN_CTEAT
#define ext_nin_pin_make(name, port, pin) \
	extern const port_in_pin_type name;   \
	extern uint8_t name##_pin_in_st(void)
#else
#define ext_nin_pin_make(name, port, pin)                                           \
	uint8_t name##_pin_in_st(void) { return !((ext_port_in[port] >> pin) & 0x01); } \
	const port_in_pin_type name = {                                                 \
		name##_pin_in_st}
#endif

/*******************************************************************************
 * @brief   同相多输出OUT定义
 *******************************************************************************/
#ifndef PORT_PIN_CTEAT
#define port_multi_out_pin_make(name, port, pin, link) \
	extern const port_multi_out_pin_type name;         \
	extern void name##_pin_en(void);                   \
	extern void name##_pin_dis(void);                  \
	extern void name##_pin_out(uint8_t st);            \
	extern void name##_pin_tog(void);                  \
	extern uint8_t name##_pin_out_st(void);
#else
#define port_multi_out_pin_make(name, port, pin, link)                  \
	const port_multi_out_pin_type *name##_next = link;                  \
	void name##_pin_en(void)                                            \
	{                                                                   \
		gpio_out_high(port, pin);                                       \
		if (name##_next)                                                \
			name##_next->en();                                          \
	}                                                                   \
	void name##_pin_dis(void)                                           \
	{                                                                   \
		gpio_out_low(port, pin);                                        \
		if (name##_next)                                                \
			name##_next->dis();                                         \
	}                                                                   \
	void name##_pin_out(uint8_t st)                                     \
	{                                                                   \
		gpio_out_set(port, pin, st);                                    \
		if (name##_next)                                                \
			name##_next->out(st);                                       \
	}                                                                   \
	uint8_t name##_pin_out_st(void) { return gpio_out_get(port, pin); } \
	const port_multi_out_pin_type name = {                              \
		name##_pin_en,                                                  \
		name##_pin_dis,                                                 \
		name##_pin_out,                                                 \
		name##_pin_out_st,                                              \
		&name##_next}
#endif

/*******************************************************************************
 * @brief   反相多输出OUT定义
 *******************************************************************************/
#ifndef PORT_PIN_CTEAT
#define port_multi_nout_pin_make(name, port, pin, link) \
	extern const port_multi_out_pin_type name;          \
	extern void name##_pin_en(void);                    \
	extern void name##_pin_dis(void);                   \
	extern void name##_pin_out(uint8_t st);             \
	extern void name##_pin_tog(void);                   \
	extern uint8_t name##_pin_out_st(void);
#else
#define port_multi_nout_pin_make(name, port, pin, link)                 \
	const port_multi_out_pin_type *name##_next = link;                  \
	void name##_pin_en(void)                                            \
	{                                                                   \
		gpio_out_low(port, pin);                                        \
		if (name##_next)                                                \
			name##_next->en();                                          \
	}                                                                   \
	void name##_pin_dis(void)                                           \
	{                                                                   \
		gpio_out_high(port, pin);                                       \
		if (name##_next)                                                \
			name##_next->dis();                                         \
	}                                                                   \
	void name##_pin_out(uint8_t st)                                     \
	{                                                                   \
		gpio_out_set(port, pin, !st);                                   \
		if (name##_next)                                                \
			name##_next->out(st);                                       \
	}                                                                   \
	uint8_t name##_pin_out_st(void) { return gpio_out_get(port, pin); } \
	const port_multi_out_pin_type name = {                              \
		name##_pin_en,                                                  \
		name##_pin_dis,                                                 \
		name##_pin_out,                                                 \
		name##_pin_out_st,                                              \
		&name##_next}
#endif

/*******************************************************************************
 * @brief   同相外部IO定义
 *******************************************************************************/
#ifndef PORT_PIN_CTEAT
#define ext_multi_io_pin_make(name, port, pin, link) \
	extern const port_multi_out_pin_type name;       \
	extern void name##_pin_en(void);                 \
	extern void name##_pin_dis(void);                \
	extern void name##_pin_out(uint8_t st);          \
	extern uint8_t name##_pin_out_st(void);
#else
#define ext_multi_io_pin_make(name, port, pin, link)                    \
	const port_multi_out_pin_type *name##_next = link;                  \
	void name##_pin_en(void)                                            \
	{                                                                   \
		ext_port_out[port][pin] = 1;                                    \
		if (name##_next)                                                \
			name##_next->en();                                          \
	}                                                                   \
	void name##_pin_dis(void)                                           \
	{                                                                   \
		ext_port_out[port][pin] = 0;                                    \
		if (name##_next)                                                \
			name##_next->dis();                                         \
	}                                                                   \
	void name##_pin_out(uint8_t st)                                     \
	{                                                                   \
		ext_port_out[port][pin] = st;                                   \
		if (name##_next)                                                \
			name##_next->out(st);                                       \
	}                                                                   \
	uint8_t name##_pin_out_st(void) { return ext_port_out[port][pin]; } \
	const port_multi_out_pin_type name = {                              \
		name##_pin_en,                                                  \
		name##_pin_dis,                                                 \
		name##_pin_out,                                                 \
		name##_pin_out_st, &name##_next}
#endif

/*******************************************************************************
 * @brief   同相外部IO定义
 *******************************************************************************/
#ifndef PORT_PIN_CTEAT
#define ext_multi_nio_pin_make(name, port, pin, link) \
	extern const port_multi_out_pin_type name;        \
	extern void name##_pin_en(void);                  \
	extern void name##_pin_dis(void);                 \
	extern void name##_pin_out(uint8_t st);           \
	extern uint8_t name##_pin_out_st(void);
#else
#define ext_multi_nio_pin_make(name, port, pin, link)                   \
	const port_multi_out_pin_type *name##_next = link;                  \
	void name##_pin_en(void)                                            \
	{                                                                   \
		ext_port_out[port][pin] = 0;                                    \
		if (name##_next)                                                \
			name##_next->en();                                          \
	}                                                                   \
	void name##_pin_dis(void)                                           \
	{                                                                   \
		ext_port_out[port][pin] = 1;                                    \
		if (name##_next)                                                \
			name##_next->dis();                                         \
	}                                                                   \
	void name##_pin_out(uint8_t st)                                     \
	{                                                                   \
		ext_port_out[port][pin] = !st;                                  \
		if (name##_next)                                                \
			name##_next->out(st);                                       \
	}                                                                   \
	uint8_t name##_pin_out_st(void) { return ext_port_out[port][pin]; } \
	const port_multi_out_pin_type name = {                              \
		name##_pin_en,                                                  \
		name##_pin_dis,                                                 \
		name##_pin_out,                                                 \
		name##_pin_out_st, &name##_next}
#endif

/*******************************************************************************
 * @brief   应用层 输出 定义
 *******************************************************************************/
#if APP_IO_MULTI_LINK > 0
#define app_io_out_make(name, port, pin, link) port_multi_out_pin_make(name, port, pin, link)
#define app_io_nout_make(name, port, pin, link) port_multi_nout_pin_make(name, port, pin, link)
#define app_eio_out_make(name, port, pin, link) ext_multi_io_pin_make(name, port, pin, link)
#define app_eio_nout_make(name, port, pin, link) ext_multi_nio_pin_make(name, port, pin, link)
#else
#define app_io_out_make(name, port, pin, link) port_out_pin_make(name, port, pin)
#define app_io_nout_make(name, port, pin, link) port_nout_pin_make(name, port, pin)
#define app_eio_out_make(name, port, pin, link) ext_io_pin_make(name, port, pin)
#define app_eio_nout_make(name, port, pin, link) ext_nio_pin_make(name, port, pin)
#endif

#endif
